package com.open.gen.main;

import com.alibaba.fastjson.JSON;
import com.open.gen.po.MetaData;
import com.open.gen.po.TableConfig;
import com.open.gen.util.FreeMarkerUtils;
import com.open.gen.util.MappingUtil;
import com.open.gen.util.MetaMapping;
import com.open.gen.util.PropUtils;
import org.apache.commons.io.FileUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import java.io.*;
import java.util.*;

public class Generator {
    private static Logger log = LoggerFactory.getLogger(Generator.class);

    public static void main(String[] args) {
        try {
            new Generator();
        } catch (Exception e) {
            log.error("生成代码发生异常", e);
        }
    }

    // 生成代码
    public Generator() {
        // 创建输出目录
        File outputDirc = new File("generated-files");
        if (!outputDirc.exists()) {
            outputDirc.mkdirs();
        }

        List<TableConfig> TableConfigs = getTableConfig();
        log.info("配置信息：{}", TableConfigs);
        for (TableConfig tableConfig : TableConfigs) {
            try {
                generateCode(outputDirc, tableConfig.getName(), tableConfig.getModuleName(), tableConfig.getPackageName());
            } catch (Exception e) {
                log.error("生成模版发生异常:", e);
            }
        }
    }

    // 生成模版
    private void generateCode(File outputDirc, String tableName, String moduleName, String packageName) throws IOException {
        // 生成模块目录
        File moduleDirc = new File(outputDirc, moduleName);
        if (!moduleDirc.exists()) {
            moduleDirc.mkdir();
        }

        // 构建模版数据
        Map<String, Object> templateData = getTemplateData(tableName, moduleName, packageName);

        // 生成实体类
        File poPackageDirc = new File(moduleDirc, "model/po");
        poPackageDirc.mkdirs();
        String poFileName = poPackageDirc.getCanonicalPath() + File.separator + MappingUtil.getEntityName(tableName) + ".java";
        generateEntity(templateData, poFileName);

        // 生成DAO类
        File daoPackageDirc = new File(moduleDirc, "model/dao");
        daoPackageDirc.mkdirs();
        String daoFileName = daoPackageDirc.getCanonicalPath() + File.separator + MappingUtil.getEntityName(tableName) + "Dao.java";
        generateDao(templateData, daoFileName);

        // 生成MAPPER
        File mapperPackageDirc = new File(moduleDirc, "mapper");
        mapperPackageDirc.mkdirs();
        String mapperFileName = mapperPackageDirc.getCanonicalPath() + File.separator + MappingUtil.getEntityName(tableName) + "Mapper.xml";
        generateMapper(templateData, mapperFileName);

        // 生成Service类
        File servicePackageDirc = new File(moduleDirc, "service");
        servicePackageDirc.mkdirs();
        String serviceFileName = servicePackageDirc.getCanonicalPath() + File.separator + MappingUtil.getEntityName(tableName) + "Service.java";
        generateService(templateData, serviceFileName);

        // 生成Controller
        File controllerPackageDirc = new File(moduleDirc, "controller");
        controllerPackageDirc.mkdirs();
        String controllerFileName = controllerPackageDirc.getCanonicalPath() + File.separator + MappingUtil.getEntityName(tableName) + "Controller.java";
        generateController(templateData, controllerFileName);
    }

    // 获取表配置
    private List<TableConfig> getTableConfig() {
        List<TableConfig> list = new ArrayList<TableConfig>();
        try {
            Resource entityResource = new ClassPathResource("config.xml");
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(entityResource.getFile());
            Element root = document.getRootElement();
            Iterator<Element> iterator = root.elementIterator();
            while (iterator.hasNext()) {
                Element element = iterator.next();
                String name = element.attribute("name").getValue();
                String moduleName = element.attribute("moduleName").getValue();
                String packageName = element.attribute("packageName").getValue();
                TableConfig tableConfig = new TableConfig();
                tableConfig.setName(name);
                tableConfig.setModuleName(moduleName);
                tableConfig.setPackageName(packageName);
                list.add(tableConfig);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    // 构建模版数据
    private Map<String, Object> getTemplateData(String tableName, String moduleName, String packageName) {
        String className = MappingUtil.getEntityName(tableName);
        Map<String, Object> templateData = new HashMap<String, Object>();
        List<MetaData> columnList = new MetaMapping(tableName).getColumnList();
        log.info("columnList: {}", JSON.toJSONString(columnList));

        templateData.put("tableName", tableName);
        templateData.put("className", className);
        templateData.put("packageName", packageName);
        templateData.put("moduleName", moduleName);
        templateData.put("columnList", columnList);
        return templateData;
    }

    // 生成Entity类
    private void generateEntity(Map<String, Object> templateData, String fileName) {
        try {
            Resource entityResource = new ClassPathResource("/templates/entity.ftl");
            String templateString = FileUtils.readFileToString(entityResource.getFile(), "UTF-8");
            String codeStr = FreeMarkerUtils.renderString(templateString, templateData);
            FileUtils.write(new File(fileName), codeStr, "UTF-8");
        } catch (IOException e) {
            log.error("读取文件发生异常，异常详情：", e);
        }
    }

    // 生成Dao类
    private void generateDao(Map<String, Object> templateData, String fileName) {
        try {
            Resource resource = new ClassPathResource("/templates/dao.ftl");
            String templateString = FileUtils.readFileToString(resource.getFile(), "UTF-8");
            String codeStr = FreeMarkerUtils.renderString(templateString, templateData);
            FileUtils.write(new File(fileName), codeStr, "UTF-8");
        } catch (IOException e) {
            log.error("读取文件发生异常，异常详情：", e);
        }
    }

    // 生成Mapper类
    private void generateMapper(Map<String, Object> templateData, String fileName) {
        try {
            Resource resource = new ClassPathResource("/templates/mapper.ftl");
            String templateString = FileUtils.readFileToString(resource.getFile(), "UTF-8");
            String codeStr = FreeMarkerUtils.renderString(templateString, templateData);
            FileUtils.write(new File(fileName), codeStr, "UTF-8");
        } catch (IOException e) {
            log.error("读取文件发生异常，异常详情：", e);
        }
    }

    // 生成Service类
    private void generateService(Map<String, Object> templateData, String fileName) {
        try {
            Resource resource = new ClassPathResource("/templates/service.ftl");
            String templateString = FileUtils.readFileToString(resource.getFile(), "UTF-8");
            String codeStr = FreeMarkerUtils.renderString(templateString, templateData);
            FileUtils.write(new File(fileName), codeStr, "UTF-8");
        } catch (IOException e) {
            log.error("读取文件发生异常，异常详情：", e);
        }
    }

    // 生成Controller类
    private void generateController(Map<String, Object> templateData, String fileName) {
        try {
            Resource resource = new ClassPathResource("/templates/controller.ftl");
            String templateString = FileUtils.readFileToString(resource.getFile(), "UTF-8");
            String codeStr = FreeMarkerUtils.renderString(templateString, templateData);
            FileUtils.write(new File(fileName), codeStr, "UTF-8");
        } catch (IOException e) {
            log.error("读取文件发生异常，异常详情：", e);
        }
    }

}
